"""
Utility to locate and register libstdc++ pretty-printers automatically.
"""

from __future__ import annotations

import glob
import os
import subprocess
from typing import Optional

import gdb  # type: ignore

def log(message: str) -> None:
    gdb.write(f"[algviz][pretty] {message}\n")

def _check_path(path: str) -> Optional[str]:
    if not os.path.isdir(path):
        return None
    target = os.path.join(path, "libstdcxx", "v6", "printers.py")
    if os.path.isfile(target):
        return path
    return None

def _check_env_var(var: str) -> Optional[str]:
    value = os.environ.get(var)
    if value:
        log(f"env {var}={value}")
        hit = _check_path(value)
        if hit:
            log("found printers.py via env var")
            return hit
        log("env path exists but printers.py missing")
    return None

def _probe_compiler_python_dir(compiler: str) -> Optional[str]:
    try:
        out = subprocess.check_output([compiler, "-print-file-name=python"])
        candidate = out.decode().strip()
        log(f"{compiler} -print-file-name=python -> {candidate!r}")
        if candidate and candidate != "python":
            return _check_path(candidate)
        log("compiler returned bare 'python' or empty path")
    except Exception as exc:
        log(f"{compiler} -print-file-name=python failed: {exc}")
    return None

def _compiler_major_version(compiler: str) -> Optional[str]:
    try:
        out = subprocess.check_output([compiler, "-dumpversion"])
        major = out.decode().strip().split(".")[0]
        log(f"{compiler} major version: {major}")
        return major
    except Exception as exc:
        log(f"{compiler} -dumpversion failed: {exc}")
    return None

def _search_common_paths(major: Optional[str]) -> Optional[str]:
    patterns = []
    if major:
        patterns += [
            f"/usr/share/gcc-{major}/python",
            f"/usr/lib/gcc/*/{major}*/python",
            f"/usr/lib64/gcc/*/{major}/python",
        ]
    patterns += [
        "/usr/share/gcc/python",
        "/usr/share/gcc-*/python",
        "/usr/lib/gcc/*/*/python",
        "/usr/lib/gcc/*/*/*/python",
        "/usr/lib64/gcc/*/*/python",
        "/usr/local/share/gcc-*/python",
    ]

    for pattern in patterns:
        for path in glob.glob(pattern):
            log(f"checking {path}")
            hit = _check_path(path)
            if hit:
                log(f"auto-search hit: {hit}")
                return hit
    return None

def _find_pretty_printer_dir() -> Optional[str]:
    env_vars = ["STD_PRINTER_PATH", "GCC_PYTHON_DIR", "GDB_STD_PRINTER_PATH"]
    for var in env_vars:
        hit = _check_env_var(var)
        if hit:
            return hit

    compiler = os.environ.get("CXX", "g++")
    hit = _probe_compiler_python_dir(compiler)
    if hit:
        return hit

    major = _compiler_major_version(compiler)
    hit = _search_common_paths(major)
    if hit:
        return hit

    return None

def load_pretty_printers() -> bool:
    directory = _find_pretty_printer_dir()
    if not directory:
        log("failed to locate libstdc++ pretty-printers. set STD_PRINTER_PATH manually.")
        return False

    import sys
    if directory not in sys.path:
        sys.path.insert(0, directory)

    try:
        from libstdcxx.v6.printers import register_libstdcxx_printers
        register_libstdcxx_printers(None)
        log(f"registered printers from {directory}")
        return True
    except Exception as exc:
        log(f"import/register failed: {exc}")
        return False